#include "drv_flash.h"



/**
  * @brief  read data using halfword mode
  * @param  read_addr: the address of reading
  * @param  p_buffer: the buffer of reading data
  * @param  num_read: the number of reading data
  * @retval none
  */
void flash_read(uint32_t read_addr, uint16_t *p_buffer, uint16_t num_read)
{
	uint16_t i;
	for(i = 0; i < num_read; i++)
	{
		p_buffer[i] = *(uint16_t*)(read_addr);
		read_addr += 2;
	}
}

/**
  * @brief  write data using halfword mode without checking
  * @param  write_addr: the address of writing
  * @param  p_buffer: the buffer of writing data
  * @param  num_write: the number of writing data
  * @retval none
  */
void flash_write(uint32_t write_addr, uint16_t *p_buffer, uint16_t num_write)
{
	uint16_t i;
	flash_unlock();

	for(i = 0; i < num_write; i++)
	{
		flash_halfword_program(write_addr, p_buffer[i]);
		write_addr += 2;
	}
	flash_lock();
}


/**
  * @brief  write data using halfword mode without checking
  * @param  write_addr: the address of writing
  * @param  p_buffer: the buffer of writing data
  * @param  num_write: the number of writing data
  * @retval none
  */
void flash_write_nocheck(uint32_t write_addr, uint16_t *p_buffer, uint16_t num_write)
{
	uint16_t i;
	flash_unlock();
	flash_sector_erase(write_addr);
	for(i = 0; i < num_write; i++)
	{
		flash_halfword_program(write_addr, p_buffer[i]);
		write_addr += 2;
	}
	flash_lock();
}


#if 0

#define SECTOR_SIZE		1024
uint16_t flash_buf[SECTOR_SIZE / 2];

/**
  * @brief  write data using halfword mode with checking
  * @param  write_addr: the address of writing
  * @param  p_buffer: the buffer of writing data
  * @param  num_write: the number of writing data
  * @retval none
  */
void flash_write_check(uint32_t write_addr, uint16_t *p_buffer, uint16_t num_write)
{
	uint32_t offset_addr;
	uint32_t sector_position;
	uint16_t sector_offset;
	uint16_t sector_remain;
	uint16_t i;

	flash_unlock();
	offset_addr = write_addr - FLASH_BASE;
	sector_position = offset_addr / SECTOR_SIZE;
	sector_offset = (offset_addr % SECTOR_SIZE) / 2;
	sector_remain = SECTOR_SIZE / 2 - sector_offset;
	if(num_write <= sector_remain)
		sector_remain = num_write;
	while(1)
	{
		flash_read(sector_position * SECTOR_SIZE + FLASH_BASE, flash_buf, SECTOR_SIZE / 2);
		for(i = 0; i < sector_remain; i++)
		{
			if(flash_buf[sector_offset + i] != 0xFFFF)
				break;
		}
		if(i < sector_remain)
		{
			flash_sector_erase(sector_position * SECTOR_SIZE + FLASH_BASE);
			for(i = 0; i < sector_remain; i++)
			{
				flash_buf[i + sector_offset] = p_buffer[i];
			}
			flash_write_nocheck(sector_position * SECTOR_SIZE + FLASH_BASE, flash_buf, SECTOR_SIZE / 2);
		}
		else
		{
			flash_write_nocheck(write_addr, p_buffer, sector_remain);
		}
		if(num_write == sector_remain)
			break;
		else
		{
			sector_position++;
			sector_offset = 0;
			p_buffer += sector_remain;
			write_addr += (sector_remain * 2);
			num_write -= sector_remain;
			if(num_write > (SECTOR_SIZE / 2))
				sector_remain = SECTOR_SIZE / 2;
			else
				sector_remain = num_write;
		}
	}
	flash_lock();
}



#undef LOG_LVL
#define LOG_LVL		ELOG_LVL_DEBUG
#define LOG_TAG		"drv_flash"

#include "log.h"


extern error_status buffer_compare(uint16_t* p_buffer1, uint16_t* p_buffer2, uint16_t buffer_length);

void flash_test(void)
{

#define TEST_BUFEER_SIZE                 500
#define TEST_FLASH_ADDRESS_START         (0x08000000 + 1024 * 60)

	uint32_t index=0;
	uint16_t buffer_write[TEST_BUFEER_SIZE];
	uint16_t buffer_read[TEST_BUFEER_SIZE];

	for(index = 0; index < TEST_BUFEER_SIZE; index++)
	{
		buffer_write[index] = index;
	}

	log_d("internal flash write test>>>>>>>>");

	flash_write(TEST_FLASH_ADDRESS_START, buffer_write, TEST_BUFEER_SIZE);
	log_d("flash write ok>>>>>>>>");
	log_dump_hex("write", (uint8_t *)buffer_write, TEST_BUFEER_SIZE*2, 16);

	log_d("internal flash read test<<<<<<<<");

	flash_read(TEST_FLASH_ADDRESS_START, buffer_read, TEST_BUFEER_SIZE);
	log_d("internal flash read ok>>>>>>>>");
	log_dump_hex("write", (uint8_t *)buffer_read, TEST_BUFEER_SIZE*2, 16);

//	if(ERROR !=	buffer_compare(buffer_write, buffer_read, TEST_BUFEER_SIZE*2))
//		log_d("internal flash read and write test ok!");
//	else
//		log_e("internal flash read and write test error!!!!!!");
}



#endif




